版本管理工具的作用
1. 备份文件
就像我们使用U盘网盘备份电影、文档一样,写代码的时候也需要有个东西帮我们备份,每当代码有修改的时候,提交我们的修改给版本管理工具进行保管,万一电脑坏了还能从备份里恢复回来,其实备份是我们项目管理中最基本的一个事情,因为每天的工作结果都保存在这个文件当中,如果某天因为一些不可预料的因素导致文件丢失,就像玩游戏时打 BOSS
,如果不提前存档,那么打输了,之前的游戏记录就全消失了,还得重新打。
2. 记录历史
版本管理工具会帮助我们保管文件,但是版本管理工具的保管和网盘,U盘的保管不尽相同,网盘和U盘帮我们保存的是一个最新的文件状态,而历史的版本是找不回来的,比如说网盘里有一个文件,是用来记录每天的日记,有一天我们想知道某一天的某一行是哪天,几点钟加上去的,这个信息网盘或者U盘是没有办法告诉我们的,除非我们自己在这个地方加一条改动记录。
而版本管理工具是在我们每一次修改完,提交给版本管理工具后,它都会留一份备份,它会记录着当时这个修改是几点几分,是谁进行的修改,那么这样的话,当我们需要去回溯,去查找这些信息的时候,版本管理工具是可以告诉我们的。
3. 回到过去
版本管理工具会将我们每一次的修改做一个备份,如果我们不小心删除了某一个日记,并将这个删除也提交给了版本管理工具,通过版本管理工具,我们是可以通过历史备份把它恢复过来的,就好像是一个机器猫的时光机,我们可以让我们的文件恢复到任意过去的一个时间的的状态。
4. 多端共享
版本管理工具的另一个特性是我们托管的文件可以在多端进行同步,类似于苹果的 iCould
服务,我们可以在不同的设备上拿到最新的文件。比如说某天我在公司的电脑上提交了一个文件,可能是我们正在进行的一个工作,而我们没有做完就提交到了版本管理工具。那么我们可以回到家之后,通过版本管理工具,把我们之前提交的做到一半的的文件拿回来继续写,这就是多端共享。
5. 团队协作
软件开发项目和复仇者联盟团伙作案其实很相似,在我们的团队中,虽然各个都可以独挡一面,但是如果配合不好的话,也会相互扯后腿。版本管理工具就是帮我们解决这种冲突的,即使我们发生了一些冲突,版本管理工具也可以帮我们迅速的解决我们的一些冲突,将负面影响降低到最小。
版本管理工具区别
版本管理工具分为两种,集中式和分布式,集中式的版本管理工具代表如 CVS
和 SVN
,是比较老的版本工具,分布式的如 Git
和 GitHub
,是新型的版本管理工具。
所谓集中式,就是说它必须要有一个中心服务器来放置最新的文件,如果不联网就没有办法提交和查看。
而分布式的版本管理工具,每一个拥有版本库的人都可以在不联网的情况下快速完成文件的提交、查看记录、删除等操作,在效率上比集中式要高很多。
其中 Git
和 GitHub
经常出现在一起,导致很多人认为它们是一个东西,其实不然,GitHub
实际上是一个程序员社区网站,在这个网站上程序员可以托管他自己的代码库,当然托管这件事是基于 Git
完成的。
GitHub客户端下载和使用
点击进入 GitHub桌面版 下载对应的版本,以 Mac
为例,将 GitHub
拖进 Applications
,打开后点击Continue
,输入 GitHub
的用户名和密码 。
往客户端里面添加项目仓库有三种方式。点击上图箭头所指的 +
号,就可以看到了,也就是下面图中的Add
,Create
,Clone
这三种形式。
add
:来源是你本地机器上已经存在的项目,填写它的文件夹位置,然后点击 Create&Add Repository
,如果这个项目本身就是一个 Git仓库
了,就直接添加进来,如果不是,就把它变成一个 Git仓库
(其实也就是在项目内创建一个 .git 文件夹)然后再添加进客户端。
create
:就是自己新建项目。填写项目名,选择项目存放位置,然后点 Create Repository
按钮,仓库就创建好了。
clone
:就是从 GitHub.com
上往本地 clone
。选中一个项目,在本地硬盘上找一个位置存放起来就可以了。
Clone的工作原理
项目修改
在你对项目中的文件进行修改后,要特别留意以下几点:
|
|
删除项目
要删除一个仓库,就到下图左侧列表的项目名字上,右击,然后点 Remove
就行了。简单说说另外几项,Atom 是 GitHub
公司开发的开源免费的代码编辑器,Terminal
是命令行终端,Finder
是文件浏览器。
查看修改历史
进入 History
,红框内依次是修改留言、修改人、上个版本号、修改时间。
撤销最近一次的修改
值得注意的是 Undo
适用于未同步到 GitHub
之前的操作,如果已经进行过同步,需要进入 History
,点击Revert This Commit
进行撤销:
发布项目到 GitHub
同步项目到GitHub
当项目发布以后,Publish
就会变成 Sync
了,以后这个项目的下的文件改变以后,可以点击 Sync
同步到 GitHub
。
Sync 的工作原理
GitHub 分支
Git
最核心的操作对象是版本( commit )
,版本最核心的操作技巧就是分支(branch)
。
仓库创建后,一旦有了新 commit
,默认就会放到一个分支上,名字叫 master
。前面看到的多个版本组成的一条历史线,就是 master
分支。但是一个仓库内,用户可以自己创建其他的分支,可以有多条历史线。
master
这个名字,一般中文叫【主分支】,其实从技术底层来讲它跟其他我们自己要创建的分支没有区别,只不过它是天生的默认分支。实际工程项目中会人为的给它一个重要的使命,存放稳定代码。就像 GitHub
公司倡导的。
master 分支上的所有代码都应该是可以部署的。
意思就是 master
分支上的代码是随时可以放到产品服务器上跑的代码。这样,如果想开发一个新功能,可以新开分支。 想象一下历史线上有很多节,每个版本就是一节。一个分支相当于一跟竹子,一节节的往上长。
但是实际上在底层并不是每个分支都拷贝出自己独立的一条历史线。其实 master
本身只是一个指针,指向 master
分支上最新的一个版本。这样由于每个 commit
都可以顺藤摸瓜找到自己的前一个 commit
,那么这条历史线就可以确定了。
master 的原理
创建新分支
点击所示按钮,就会弹出对话框。Create new branch
就是来创建一个分支。所谓 from master
意思是基于 master
分支,拥有和 master
一样的历史。
分支的原理
就是就是创建一个新的指针,跟 master
指针指向同一个版本,根本没有拷贝历史线。
如果现在我们对项目做一下修改,然后 commit
了。那么移动的只是 idea
指针,master
不变。就成了这样:
现在 master
分支包含两个版本 C1 和 C2
,idea
分支包含三个版本 C1,C2,C3
。
默认情况下这个 idea
分支只是存在于本地,如果想在远端仓库上发布这个分支,就点一下 idea
分支右侧的Publish
按钮。现在这个项目就有了两个分支。
删除分支
删除分支不在图形界面中,在顶部的控制栏 Branch - Delete
。如果只删除 GitHub.com
的分支,而不删除本地的分支,使用 Branch - Unpublish
。
分支合并
分支合并在顶部的控制栏 Branch - Merge
,他会新成了一个 C5
,这是一个 融合版本( Merge Commit )
,这个合并比较特殊,里面一般没有修改内容,它的作用主要是把两个分支合并起来。怎么合并的呢?融合版本包含两个版本,一个指向 C2
,一个指向 C3
。
master
分支指针指向了 merge commit
,也就自动拥有了 idea
分支上的 C3
这个版本了。idea
分支一般现在就可以删除了。
分支融合的工作原理
代码冲突
实际中经常有这样的情况,我们正在 idea
分支上开发一个功能。但是这个时候突然发现了一个紧急的问题需要修复,所以会直接到 master
分支上,做一个 commit
来解决这个紧急的问题。然后会来继续到 idea
上开发。
其他的情形也有,总之这样就会出现,两个不同分支上并行开发,同时都有新的 commit
,这个一般没有问题,一样可以直接 merge
,如下图:
但是如果在两个分支上改动了同一个地方,合并的就会出现代码冲突。 因为 Git 不知道该听哪个分支的,所以只能报出冲突的位置,让开发者手动解决。
合并远端分支
现在我们的本地仓库叫 TestRepository
,GitHub.com
上也托管了这个仓库。那么自然就有一个本地master
分支,和一个 远端master
分支 ,这两个分支虽然名字都叫 master
,但是本质上也是两个分支,也存在分支合并的问题。
举例来说,我们在 GitHub.com
网页上,修改一下项目,把修改内容 commit
到 master
分支之上。这样,远端master
分支就比 本地master
分支多了一个 commit
。此时在我们的客户端点 sync
按钮执行同步,这个 commit
就会直接被 pull
到本地。
另外一种情况,在没有 sync
之前,我们在本地也做了一个 commit
,也就是 本地master
和 远端master
出现了并行开发的情况,这种情况是非常常见的。这个时候我们执行 sync
,跟本地两个分支合并是一样的,一般也会生成一个 merge commit
,在本地客户端和 GitHub.com
上的历史线都可以看到。
在特定条件下,点击 sync
按钮两个分支合并会不使用 融合( merge )
方式,而采用 变基( rebase )
方式,这样最终不会生成一个 merge commit
。但是达成的效果是一样的,也是实现了两个分支代码的合并,处理冲突的方式也一样,所以暂时不必深究。
团队合作
前面讲的都是开发者唱独角戏,但是尽管如此也可以看出 Git
带来的便利了,比如代码写错了可以回滚,为了新功能开发可以开新分支等等。但是 Git 和 GitHub
更大的威力在于协作。
GitHub 是 Git 仓库的托管平台,让我们的项目仓库可以方便的备份同步。但是其实也许比这个还要重要的是,GitHub 是一个大家一起协作做项目的平台,是一种开发者的工作方式,引导一种看着不像流程的一种真正健康轻便的开发流程。
Github
的核心叫做 Github Flow ,网站上的各个功能都是围绕着这个核心来开发的。GitHub Flow
就是一套团队协作流程,它是一个非常轻便的,基于分支的工作流。非常适合代码部署非常频繁的团队和项目。概况来讲,它就是给一个项目开发新功能要走的几步,整个过程的核心是“拉取请求” 。
|
|
使用 GitHub Flow
进行代码开发分为两种情况,第一种是团队成员之间互相熟知,另外一种是在开源项目当中,与互不相识的开源贡献者合作。
下面我们用一个实际例子先来了解团队中的协作:
我要和 Team 合作开发一个新项目,于是我先创建这个项目,然后让 Team 具有写的权限,创建项目前面已经介绍过,下面我们让 Team 成为这个项目的协作者。
首先到项目页面,点击 Settings
一项,到项目的 Settings
页面,可以看到如下图所示的 Collaborator
选项,输入框中输入协作者的用户名,此时这个协作者就具有对这个项目的写权限了。
对于非常有把握的代码,可以直接在 本地master
开发然后 sync
到 远端master
分支上面。但是如果是比较重要的功能,就需要走完整的 GitHub Flow
流程了。
整个 GitHub Flow
的核心就是 Pull Request
,而 Pull Request
的目的就是用来引发讨论和代码审核的。
NO.1 我们来开一个新的分支,这是后面进行 Pull Request
的前提。
NO.2 现在 Team
登录以后,就会收到提醒,也就是我们所做的修改。
NO.3 Team
可以进入这个分支的版本中,进入我们所做的修改,对它留言进行讨论。发布的讨论对方会收到通知和提醒。
NO.4 当我和 Team
不断完善这个分支,并完成它时,就可以发起 Pull Request
了。
NO.5 这时就相当于告诉项目的发起者,可以将这个分支合并到 master
了。
NO.6 在大家都讨论完毕后,就可以将这个分支和 master
进行合并了:
至此,团队协作进行一个项目就完成了。